// C++ Templates 第六章：移动语义和 enable_if<>
// 主要涵盖了两个现代 C++ 中非常重要的概念：移动语义和 SFINAE（通过 enable_if<> 实现）。
// 这两个特性在模板编程中尤为重要，因为它们提供了性能优化和精确控制模板实例化的能力。

// 第一部分：移动语义
// 移动语义的基本概念
// 移动语义是 C++11 引入的一个重要特性，它允许我们"窃取"临时对象或即将销毁的对象的资源，而不是进行昂贵的复制操作。
template <typename T>
class MyContainer
{
private:
    T *data;
    size_t size;

public:
    // 移动构造函数
    MyContainer(MyContainer &&other) noexcept
        : data(other.data), size(other.size)
    {
        other.data = nullptr; // 防止双重释放
        other.size = 0;
    }

    // 移动赋值运算符
    MyContainer &operator=(MyContainer &&other) noexcept
    {
        if (this != &other)
        {
            delete[] data;
            data = other.data;
            size = other.size;
            other.data = nullptr;
            other.size = 0;
        }
        return *this;
    }
};

// 完美转发
// 完美转发允许函数模板将其参数以原始类型（保持值类别、const 等限定符）传递给其他函数。
template <typename T, typename... Args>
T *create(Args &&...args)
{
    return new T(std::forward<Args>(args)...);
}

// enable_if<>
// std::enable_if是一个模板元编程工具，用于在编译时根据条件选择性地启用或禁用模板特化。
template <bool Condition, typename T = void>
struct enable_if;
// 如果Condition为true，则enable_if有一个名为type的成员，返回类型它等于T，默认为void（不关心返回类型）；否则，enable_if没有type成员。

// 在模板中的应用：
// 1.SFINAE（Substitution Failure Is Not An Error）：利用模板替换失败不是错误的原则
// 2.约束模板：根据类型特性限制模板实例化
// 3.选择性启用函数重载：根据条件选择合适的函数重载

// 示例代码：
// 只对整数类型启用的模板函数
// 如果T是整数类型，那么td::is_integral<T>::value就为true，std::enable_if<true, bool>::type就为"bool"，否则这个模板实例化就会失败，函数重载不被考虑
// typename告诉编译器std::enable_if<std::is_integral<T>::value, bool>::type 是一个类型而不是静态成员变量或其他非类型实体
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
is_even(T t)
{
    return t % 2 == 0;
}

// 只对浮点类型启用的模板函数
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
is_even(T t)
{
    return std::fmod(t, 2.0) == 0;
}

// C++14后的简化语法
template <typename T>
std::enable_if_t<std::is_integral<T>::value, bool>
is_positive(T t)
{
    return t > 0;
}

// 与移动语义结合使用：
// enable_if常与移动语义结合使用，例如：
// 只有当T支持移动构造时才启用此重载
template <typename T>
typename std::enable_if<std::is_move_constructible<T>::value>::type
process(T &&value)
{
    // 使用移动语义处理value
}

// 当T不支持移动构造时使用此重载
template <typename T>
typename std::enable_if<!std::is_move_constructible<T>::value>::type
process(const T &value)
{
    // 使用复制语义处理value
}

// 这里定义了一个类型别名模板，它使用了几个现代C++特性：
// std::is_convertible_v<From, To>：C++17引入的变量模板，检查From类型是否可以转换为To类型
// std::enable_if_t<Condition>：C++14引入的类型别名模板，是typename std::enable_if<Condition>::type的简化形式
// 当T可以转换为std::string时，EnableIfString<T>等于void；否则，它不存在。

template <typename T>
using EnableIfString = std::enable_if_t<std::is_convertible<T, std::string>::value, typename = void>;

class Person
{
private:
    std::string name;

public:
    // 这个构造函数使用了：
    // 默认模板参数：第二个模板参数默认为EnableIfString<STR>
    // SFINAE技术：当STR不能转换为std::string时，构造函数不会被考虑

    template <typename STR, typename = EnableIfString<STR>>
    explicit Person(STR &&n) : name(std::forward<STR>(n)) {}

    // 工作原理
    // 当尝试创建Person对象时，编译器会检查构造函数参数的类型：
    // 1.如果参数可以转换为std::string（如const char*、std::string等）：
    //      EnableIfString<STR>等于void
    //      构造函数模板被实例化
    //      参数通过完美转发传递给std::string构造函数
    // 2.如果参数不能转换为std::string（如int、double等）：
    //      EnableIfString<STR> 不存在
    //      构造函数模板被排除（SFINAE原理）
    //      编译器会尝试查找其他匹配的构造函数，如果没有，则报错
}

